package com.gliese.bambook.util;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.htmlparser.Attribute;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.PrototypicalNodeFactory;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.util.SimpleNodeIterator;

public class HtmlToXmlUtils {
	final static Log log = LogFactory.getLog(HtmlToXmlUtils.class);

	/**
	 * deal with 1, width=98 to width="98" [=(\\w*)\b]
	 * 
	 * @param str
	 * @return
	 */
	public static String convertHtmlToXML(String str) {
		int groupFirstStart = -1;
		int groupFirstEnd = 0;//
		StringBuffer result = new StringBuffer();
		Pattern pattern = Pattern.compile("\\s\\b\\w*=(\\w\\S*?)[\\s|>]");
		Matcher matcher = pattern.matcher(str);
		while (matcher.find()) {
			String groupFirstStr = matcher.group(1);
			groupFirstStart = matcher.start(1);
			result.append(str.substring(groupFirstEnd, groupFirstStart));
			result.append("\"");
			result.append(groupFirstStr);
			result.append("\"");
			groupFirstEnd = matcher.end(1);
		}
		result.append(str.substring(groupFirstEnd));
		return result.toString();
	}

	public static String convertHtmlToXMLByLexer(String htmlSource)
			throws ParserException {
		htmlSource = htmlSource
				.replaceAll("<script.*?</script>|<input.*?>", "");
		Parser parser = new Parser(htmlSource);
		parser.setEncoding("GB2312");
		PrototypicalNodeFactory prototypicalNodeFactory = new PrototypicalNodeFactory();
		prototypicalNodeFactory.setTagPrototype(new TagNode() {
			@Override
			public String toTagHtml() {
				int length;
				int size;
				Vector attributes;
				Attribute attribute;
				StringBuffer ret;

				length = 2;
				attributes = getAttributesEx();
				size = attributes.size();
				for (int i = 0; i < size; i++) {
					attribute = (Attribute) attributes.elementAt(i);
					length += attribute.getLength();
				}
				ret = new StringBuffer(length);
				ret.append("<");
				for (int i = 0; i < size; i++) {
					attribute = (Attribute) attributes.elementAt(i);
					if ("=".equals(attribute.getAssignment()))
						attribute.setQuote('\"');
					attribute.toString(ret);
				}
				ret.append(">");

				return (ret.toString());
			}

		});
		prototypicalNodeFactory.registerTag(new LinkTagForBam());
		prototypicalNodeFactory.registerTag(new HtmlTagForbam());
		parser.setNodeFactory(prototypicalNodeFactory);
		NodeList list = parser.parse(null);
		NodeFilter specificNodeFilter = new SpecificTagNodesFilter();
		HtmlToXmlUtils.removeNodes(list, specificNodeFilter);
		return list.toHtml().replace("&nbsp;", " ").replace("&copy;", "@");
	}

	public static void removeNodes(NodeList srcList, NodeFilter nodeFilter) {
		NodeList nodes = srcList.extractAllNodesThatMatch(nodeFilter);
		SimpleNodeIterator sni = nodes.elements();
		while (sni.hasMoreNodes()) {
			srcList.remove(sni.nextNode());
		}
		sni = srcList.elements();
		while (sni.hasMoreNodes()) {
			NodeList childrenList = sni.nextNode().getChildren();
			if (childrenList != null)
				removeNodes(childrenList, nodeFilter);
		}
	}

	public static String getHtmlCodeByHttpMethod(HttpClient httpClient,
			HttpMethod httpMethod) throws Exception {
		httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler(3, false));

		int statusCode = httpClient.executeMethod(httpMethod);
		if (statusCode != HttpStatus.SC_OK) {
			log.error("Method failed: " + httpMethod.getStatusLine());
		}
		InputStream inputStream = httpMethod.getResponseBodyAsStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(
				inputStream));
		StringBuilder httpSb = new StringBuilder();
		String inputLine;
		while ((inputLine = br.readLine()) != null) {
			httpSb.append(inputLine);
		}
		/**
		 * filter unnormal content ,such as "<!DOCTYPE ... > ,<../> <br>
		 * "
		 */
		String httpHtml = httpSb.toString();
		try {
			httpHtml = HtmlToXmlUtils.convertHtmlToXMLByLexer(httpHtml);
		} catch (ParserException pe) {
			throw new RuntimeException(pe);
		}
		return httpHtml;

	}
}
